#include "net/EventLoopThread.h"
#include "net/EventLoop.h"
#include "Base/CurrectThread.h"
#include <cassert>

namespace toym
{
namespace net
{

EventLoopThread::EventLoopThread(ThreadInitCallback_t cb, 
                                 const std::string& threadName) 
    : m_loop(nullptr),
      m_thread(nullptr),
      m_mutex(),
      m_cond(),
      m_exiting(false),
      m_threadInitCb(cb)
{
    CurrectThread::setThreadName(threadName.c_str());
}

EventLoopThread::~EventLoopThread() {
    m_exiting = true;
    if (m_loop != nullptr) {
        m_loop->quit();
        m_thread->join();
    }
}

EventLoop* EventLoopThread::startLoop() {
    EventLoop* loop;
    m_thread.reset(new std::thread(std::bind(&EventLoopThread::threadFunc, this)));
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        while (m_loop == nullptr) {
            m_cond.wait(lock);
        }
        loop = m_loop;
    }
    return loop;
}

void EventLoopThread::threadFunc() {
    EventLoop loop;
    if (m_threadInitCb) {
        m_threadInitCb(&loop);
    }
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_loop = &loop;
        m_cond.notify_one();
    }
    loop.loop();
    
    assert(m_exiting);
    std::unique_lock<std::mutex> lock;
    m_loop = nullptr;
}

} // namespace net

} // namespace toym
